package pl.edu.agh.mobsys.activities;

import java.util.List;

import org.jivesoftware.smack.MessageListener;
import org.jivesoftware.smack.XMPPException;

import pl.edu.agh.mobsys.R;
import pl.edu.agh.mobsys.XmppApplication;
import pl.edu.agh.mobsys.data.ConnectionConfig;
import pl.edu.agh.mobsys.data.Message;
import pl.edu.agh.mobsys.persistence.MessageDataHelper;
import pl.edu.agh.mobsys.utils.Constants;
import pl.edu.agh.mobsys.utils.MessagesAdapter;
import android.app.AlertDialog;
import android.app.ListActivity;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.text.format.Time;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

/**
 * Rozmowa z normalnym agentem XMPP, nie smoa.
 * 
 * Widok z listą wiadomości.
 * */
public class Chat extends ListActivity {

	private List<Message> messages;
	private MessageDataHelper messageDataHelper;
	
	private BaseAdapter adapter;

	private String alias;

	private MessageListener listener;

	private EditText newMessage;

	org.jivesoftware.smack.Chat chat;

	private String meName;

	private XmppApplication app;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.chat);

		// odebranie wiadomości o uczestniku chatu z intentu
		alias = getIntent().getStringExtra(Constants.ACTIVATED_CONTACT);
		meName = getSharedPreferences(Constants.SHARED_PREFS_KEY_SERVER_CONFIG,
				Context.MODE_WORLD_READABLE)
				.getString(ConnectionConfig.KEY_PREFIX + "username", "me");

		// bajery z listą wiadomości
		final ListView listView = getListView();
		listView.setItemsCanFocus(false);
		listView.setChoiceMode(ListView.CHOICE_MODE_NONE);
		listView.setEmptyView((TextView) findViewById(R.id.chat_empty));

		((TextView) findViewById(R.id.chat_contact_alias)).setText(alias);

		app = (XmppApplication) getApplication();

		// załadowanie wiadomości z persystencji
		loadMessages();
		adapter = new MessagesAdapter(getBaseContext(), messages);
		setListAdapter(adapter);

		// definicja callbacka na przyjścia wiadomości
		listener = new MessageListener() {

			public void processMessage(org.jivesoftware.smack.Chat arg0,
					org.jivesoftware.smack.packet.Message arg1) {
				Time t = new Time();
				t.set(System.currentTimeMillis());
				
				// tworzenie wiadomości do wyświetlania na liście
				Message m = new Message(arg1.getBody(), arg0.getParticipant(),
						t.format("%H:%M:%S"));

				// dodanie do listy wyświetlanej
				messages.add(m);
				
				// do persystencji
				messageDataHelper.insert(m.content, m.author, m.time);

				// w wątku sterującym GUI !!!
				updateView();

				Log.i("CHAT",
						"Received message: " + m + " from: " + arg1.getFrom());
			}
		};

		// jak w gg - enterem się wysyła!
		newMessage = (EditText) findViewById(R.id.chat_new_message);
		newMessage.setOnKeyListener(new OnKeyListener() {
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				if (keyCode == KeyEvent.KEYCODE_ENTER) {
					sendMessage();
					return true;
				}
				return false;
			}
		});

		// guzik do wysyłania wiadomości
		((Button) findViewById(R.id.chat_send))
				.setOnClickListener(new OnClickListener() {

					public void onClick(View v) {
						sendMessage();
					}

				});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		super.onCreateOptionsMenu(menu);
		// czyszczenie listy z wiadomościami
		menu.add(R.string.chat_clear_messages);
		return true;
	}

	@Override
	public boolean onMenuItemSelected(int featureId, MenuItem item) {
		// czyszczenie listy z wiadomościami - jedyna opcja
		showDeleteConfirmationDialog();
		return true;
	}

	/**
	 * Czyszczenie listy z wiadomościami - popup
	 * */
	private void showDeleteConfirmationDialog() {
		// prepare the alert box
		AlertDialog.Builder alertbox = new AlertDialog.Builder(this);
		alertbox.setMessage(getResources().getString(
				R.string.chat_clear_confirmation_query));
		alertbox.setPositiveButton(
				getResources().getString(R.string.con_confirm_yes),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface arg0, int arg1) {
						messages.clear();
						adapter.notifyDataSetChanged();
						messageDataHelper.deleteAllMessages();
						Toast.makeText(getApplicationContext(),
								R.string.chat_messages_cleared,
								Toast.LENGTH_SHORT).show();
					}
				});

		alertbox.setNegativeButton(
				getResources().getString(R.string.con_confirm_no),
				new DialogInterface.OnClickListener() {
					public void onClick(DialogInterface arg0, int arg1) {
						; // nic się nie dzieje
					}
				});

		alertbox.show();
	}

	@Override
	protected void onResume() {
		super.onResume();
		chat = ((XmppApplication) getApplication()).getChat(alias, null);
		if (chat != null) {
			for(MessageListener ml: chat.getListeners()) {
				chat.removeMessageListener(ml);
			}
			chat.addMessageListener(listener);
		} else {
			Toast.makeText(getApplicationContext(),
					"Failed to create chat for alias: " + alias,
					Toast.LENGTH_SHORT).show();
		}
	}

	/**
	 * Załadowanie wiadmości z persystencji
	 * */
	private void loadMessages() {
		if (messages == null) {
			messages = app.getMessages(alias);
			messageDataHelper = app.getMessageDataHelper(alias);
		}
	}

	/**
	 * Obsługa wysyłania wiadomości wpisanej w pole <code>newMessage</code>.
	 * */
	protected void sendMessage() {
		final String message = newMessage.getText().toString();
		if (message == null || "".equals(message)) {
			return;
		}

		try {
			Time t = new Time();
			t.set(System.currentTimeMillis());
			Message m = new Message(message, meName, t.format("%H:%M:%S"));

			chat.sendMessage(m.content);
			messages.add(m);
			messageDataHelper.insert(m.content, m.author, m.time);

			updateView();
			
			Log.d("CHAT", "Message sent: " + m + " TO " + chat.getParticipant());
		} catch (XMPPException e) {
			Toast.makeText(getApplicationContext(),
					R.string.chat_failed_to_send + " : " + e.getMessage(),
					Toast.LENGTH_SHORT).show();
			e.printStackTrace();
		} finally {
			// czyszczenie pola
			newMessage.setText("");
		}

	}

	/**
	 * Bez tego widok się nie odświeży!
	 * */
	private void updateView() {
		runOnUiThread(new Runnable() {
			// w wątku UI
			public void run() {
				adapter.notifyDataSetChanged();
			}
		});
	}

}